/*
 * =====================================================================================
 *
 *       Filename:  cxm_speex_jni.cpp
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  2013年12月25日 22时50分30秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  xieminchen (mtk), hs_xieminchen@mediatek.com
 *        Company:  Mediatek
 *
 * =====================================================================================
 */

#include <jni.h>
#include <stdio.h>
#include <assert.h>
#include <speex/speex.h>
#include <speex/speex_echo.h>
#include <speex/speex_preprocess.h>
#include <android/log.h>

#include "cxm_lib_speex_EchoCancellation.h"
#include "cxm_lib_speex_Preprocessor.h"

JNIEXPORT jint JNICALL Java_cxm_lib_speex_Preprocessor_speexStateInit(
        JNIEnv *env, jobject cls, jint frameSize, jint sampleRate)
{
    return (jint)speex_preprocess_state_init(frameSize, sampleRate);
}

JNIEXPORT void JNICALL Java_cxm_lib_speex_Preprocessor_speexStateDestroy(
        JNIEnv *env, jobject cls, jint speexState)
{
    SpeexPreprocessState *state = (SpeexPreprocessState *)speexState;
    assert(NULL != state);
    speex_preprocess_state_destroy(state);
}

JNIEXPORT jint JNICALL Java_cxm_lib_speex_Preprocessor_speexRun(
        JNIEnv *env, jobject cls, jint speexState, jshortArray data)
{
    SpeexPreprocessState *state = (SpeexPreprocessState *)speexState;
    assert(NULL != state);

    // get data array
    short *dataArray = env->GetShortArrayElements(data, NULL);
    // run
    int ret = speex_preprocess_run(state, dataArray);
    // free
    if (NULL != dataArray)
        env->ReleaseShortArrayElements(data, dataArray, 0);

    return (jint)ret;
}

static int _getIntegerFromObject(JNIEnv *env, jobject cls,
        jobject data, jint *outValue)
{
    // jclass peerCls = env->GetObjectClass(data);
    *outValue = 0;

    /*
    jmethodID mGetValue = env->GetMethodID(peerCls,
            "getValue","()Ljava/lang/Integer;");
    if (mGetValue == NULL)
        return -1;
    jobject value = env->CallObjectMethod(data, mGetValue);
    if (value == NULL)
        return -1;
    */

    // getValue()
    jclass rescls = env->FindClass("java/lang/Integer");
    if (rescls == NULL)
        return -1;
    jmethodID getVal = env->GetMethodID(rescls, "intValue", "()I");
    if (getVal == NULL)
        return -1;
    // *outValue = env->CallIntMethod(value, getVal);
    *outValue = env->CallIntMethod(data, getVal);

    return 0;
}

JNIEXPORT jint JNICALL Java_cxm_lib_speex_Preprocessor_speexControl(JNIEnv *env,
        jobject cls, jint speexState, jint request, jobject param)
{
    SpeexPreprocessState *state = (SpeexPreprocessState *)speexState;
    assert(NULL != state);

    switch (request)
    {
    case SPEEX_PREPROCESS_SET_ECHO_STATE:
    case SPEEX_PREPROCESS_SET_NOISE_SUPPRESS:
    case SPEEX_PREPROCESS_SET_AGC:
    case SPEEX_PREPROCESS_SET_AGC_LEVEL:
    {
        jint setParam = 0;
        if (0 != _getIntegerFromObject(env, cls, param, &setParam) ||
                0 == setParam)
            return -1;
        if (request == SPEEX_PREPROCESS_SET_ECHO_STATE)
        {
            __android_log_print(ANDROID_LOG_INFO, "JNI",
                    "Set echo state: %d", setParam);
            return speex_preprocess_ctl(state, request, (void *)setParam);
        }
        else if (request == SPEEX_PREPROCESS_SET_AGC)
        {
            __android_log_print(ANDROID_LOG_INFO, "JNI",
                    "Set AGC state: %d", setParam);
            return speex_preprocess_ctl(state, request, (void *)&setParam);
        }
        else if (request == SPEEX_PREPROCESS_SET_AGC_LEVEL)
        {
            float setFloat = (float)setParam;
            __android_log_print(ANDROID_LOG_INFO, "JNI",
                    "Set Gain Level: %d", setParam);
            return speex_preprocess_ctl(state, request, (void *)&setFloat);
        }
        else
        {
            __android_log_print(ANDROID_LOG_INFO, "JNI",
                    "Set noise suppress: %d", setParam);
            return speex_preprocess_ctl(state, request, (void *)&setParam);
        }
    }
    default:
        return -1;
    }
}

JNIEXPORT jint JNICALL Java_cxm_lib_speex_EchoCancellation_speexEchoStateInit(
        JNIEnv *cls, jobject env, jint frameSize, jint filterLength)
{
    return (jint)speex_echo_state_init(frameSize, filterLength);
}

JNIEXPORT void JNICALL Java_cxm_lib_speex_EchoCancellation_speexEchoStateDestroy(
        JNIEnv *cls, jobject env, jint state)
{
    SpeexEchoState *speexState = (SpeexEchoState *)state;
    assert(NULL != speexState);

    speex_echo_state_destroy(speexState);
}

JNIEXPORT void JNICALL Java_cxm_lib_speex_EchoCancellation_speexEchoCapture(JNIEnv *env,
        jobject cls, jint state, jshortArray bufferIn, jshortArray bufferOut)
{
    SpeexEchoState *speexState = (SpeexEchoState *)state;
    assert(NULL != speexState);

    // get data array
    short *arrayIn = env->GetShortArrayElements(bufferIn, NULL);
    short *arrayOut = env->GetShortArrayElements(bufferOut, NULL);

    // process
    assert(NULL != arrayIn && NULL != arrayOut);
    speex_echo_capture(speexState, arrayIn, arrayOut);

    // free
    if (NULL != arrayIn)
        env->ReleaseShortArrayElements(bufferIn, arrayIn, 0);
    if (NULL != arrayOut)
        env->ReleaseShortArrayElements(bufferOut, arrayOut, 0);
}

JNIEXPORT void JNICALL Java_cxm_lib_speex_EchoCancellation_speexEchoPlayback(
        JNIEnv *env, jobject cls, jint state, jshortArray bufferIn)
{
    SpeexEchoState *speexState = (SpeexEchoState *)state;
    assert(NULL != speexState);
    // get data array
    short *arrayIn = env->GetShortArrayElements(bufferIn, NULL);
    // process
    assert(NULL != arrayIn);
    speex_echo_playback(speexState, arrayIn);
    // free
    if (NULL != arrayIn)
        env->ReleaseShortArrayElements(bufferIn, arrayIn, 0);
}

JNIEXPORT void JNICALL Java_cxm_lib_speex_EchoCancellation_speexEchoReset(
        JNIEnv *env, jobject cls, jint state)
{
    SpeexEchoState *speexState = (SpeexEchoState *)state;
    assert(NULL != speexState);

    speex_echo_state_reset(speexState);
}

